home *** CD-ROM | disk | FTP | other *** search
-
- /*****************************************************************************
- *
- * CyberSound: 14 Bit sound driver
- *
- * (c) 1995 by Christian Buchner
- *
- *****************************************************************************
- *
- * Driver.c
- */
-
- #include <exec/interrupts.h>
- #include <exec/memory.h>
- #include <exec/execbase.h>
- #include <graphics/displayinfo.h>
- #include <intuition/intuitionbase.h>
- #include <devices/audio.h>
- #include <hardware/custom.h>
- #include <hardware/intbits.h>
- #include <hardware/dmabits.h>
- #include <hardware/adkbits.h>
- #include <hardware/cia.h>
- #include <clib/alib_protos.h>
- #include <proto/graphics.h>
- #include <proto/dos.h>
- #include <stdarg.h>
-
- #include "Driver.h"
- #include "DriverBase.h"
-
- void KPrintF(UBYTE *fmt,...);
-
- #define DB(x)
-
-
- /*****************************************************************************/
-
- #define TABLE_SIZE (65536*sizeof(UWORD)) /* 2^16 UWORDS */
-
-
- /*****************************************************************************/
-
- #define DMABUF_SIZE (4*BUFFER_SIZE) /* The byte size of one audio buffer */
-
- #define LEFT_MSB (0*BUFFER_SIZE)
- #define RIGHT_MSB (1*BUFFER_SIZE)
- #define RIGHT_LSB (2*BUFFER_SIZE)
- #define LEFT_LSB (3*BUFFER_SIZE)
-
- /* Buffer layout:
-
- 1) Left channel MSB Bytes -> Audio Channel 1
- 2) Right channel MSB Bytes -> Audio Channel 2
- 3) Right channel LSB Bytes -> Audio Channel 3
- 4) Left channel LSB Bytes -> Audio Channel 4
-
- */
-
-
- /*****************************************************************************/
-
- #define AUDIO_INTERRUPTS (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
- #define INTERRUPT_USED (INTF_AUD3)
- #define INTERRUPTS_NOT_USED (INTF_AUD0|INTF_AUD1|INTF_AUD2)
-
-
- /*****************************************************************************/
-
- BOOL InitDriver( struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
- UBYTE ChannelMap[]={0xf};
- BOOL LoadSuccess=FALSE;
- BPTR FH;
- UWORD i;
-
- DB(KPrintF("\n>>> INITIALIZATION <<<\n"));
-
- if (AudioReply=CreateMsgPort())
- {
- if (AudioRequest=CreateIORequest(AudioReply,sizeof(struct IOAudio)))
- {
- AudioRequest->ioa_Request.io_Message.mn_Node.ln_Pri=127;
- AudioRequest->ioa_Data=ChannelMap;
- AudioRequest->ioa_Length=sizeof(ChannelMap);
- AudioRequest->ioa_Request.io_Flags=ADIOF_NOWAIT;
-
- if (!OpenDevice("audio.device",0,(struct IORequest*)AudioRequest,0))
- {
- if (ConversionTable=AllocVec(TABLE_SIZE,MEMF_ANY))
- {
- if (AdditiveArray=AllocVec(256,MEMF_ANY))
- {
- if (FH=Open("ENV:CyberSound/SoundDrivers/14Bit_Calibration",MODE_OLDFILE))
- {
- if (Read(FH,AdditiveArray,256)==256)
- {
- LoadSuccess=TRUE;
- }
- Close(FH);
- }
- if (!LoadSuccess)
- {
- for (i=0;i<255;i++) AdditiveArray[i]=0x55;
- AdditiveArray[255]=0x7f;
- }
- CreateTable(ConversionTable,AdditiveArray);
- CurrentFormat=STREAM_16BIT_MOTOROLA;
-
- AudioVector.is_Node.ln_Type=
- NOPVector.is_Node.ln_Type=NT_INTERRUPT;
- AudioVector.is_Node.ln_Name=
- NOPVector.is_Node.ln_Name="14 bit driver";
- AudioVector.is_Data=
- NOPVector.is_Data=db;
- AudioVector.is_Code=(void*)(&AudioInterrupt);
- NOPVector.is_Code=(void*)(&NOPInterrupt);
-
- custom->dmacon= DMAF_AUDIO;
- custom->adkcon= ADKF_USE3PN|ADKF_USE2P3|
- ADKF_USE1P2|ADKF_USE0P1|
- ADKF_USE3VN|ADKF_USE2V3|
- ADKF_USE1V2|ADKF_USE0V1;
-
- OldAudVector0=SetIntVector(INTB_AUD0,&NOPVector);
- OldAudVector1=SetIntVector(INTB_AUD1,&NOPVector);
- OldAudVector2=SetIntVector(INTB_AUD2,&NOPVector);
- OldAudVector3=SetIntVector(INTB_AUD3,&AudioVector);
-
- custom->intena=custom->intreq=AUDIO_INTERRUPTS;
- custom->intena=INTF_SETCLR|INTERRUPT_USED;
-
- NestLevel=0;
- DriverFlags = FLGF_NEEDIRQ;
-
- if (SetBuffers(1024,16,db))
- {
- return(TRUE);
- }
- }
- }
- }
- }
- }
- DeInitDriver(db);
- return(FALSE);
- }
-
-
- /*****************************************************************************/
-
- void DeInitDriver( struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- DB(KPrintF("\n>>> DE-INITIALIZATION <<<\n"));
-
- if (AudioRequest)
- {
- if (AudioRequest->ioa_Request.io_Device)
- {
- FreeBuffers(db);
-
- custom->intena=custom->intreq=AUDIO_INTERRUPTS;
-
- if (OldAudVector0) SetIntVector(INTB_AUD0,OldAudVector0);
- if (OldAudVector1) SetIntVector(INTB_AUD1,OldAudVector1);
- if (OldAudVector2) SetIntVector(INTB_AUD2,OldAudVector2);
- if (OldAudVector3) SetIntVector(INTB_AUD3,OldAudVector3);
-
- if (AdditiveArray)
- {
- FreeVec(AdditiveArray);
- AdditiveArray=NULL;
- }
-
- if (ConversionTable)
- {
- FreeVec(ConversionTable);
- ConversionTable=NULL;
- }
-
- CloseDevice((struct IORequest*)AudioRequest);
- AudioRequest->ioa_Request.io_Device=NULL;
- }
- DeleteIORequest(AudioRequest);
- AudioRequest=NULL;
- }
- if (AudioReply)
- {
- DeleteMsgPort(AudioReply);
- AudioReply=NULL;
- }
- }
-
-
- /*****************************************************************************/
-
- BOOL __asm SetBuffers( register __d0 ULONG audiosize, register __d1 ULONG queuesize, register __a6 struct DriverBase *db)
- {
- BOOL Success=FALSE;
-
- FreeBuffers(db);
-
- BUFFER_SIZE=audiosize;
- QUEUE_SIZE=queuesize;
-
- if (DMABuffer1=AllocVec(DMABUF_SIZE,MEMF_CHIP))
- {
- if (DMABuffer2=AllocVec(DMABUF_SIZE,MEMF_CHIP))
- {
- if (QueueBuffer=AllocVec(QUEUE_SIZE*sizeof(struct StreamInfo),MEMF_CLEAR))
- {
- /* Flush (Initialize!) stream */
- FlushStream(db);
-
- Success=TRUE;
- }
- }
- }
- if (!Success) FreeBuffers(db);
-
- return(Success);
- }
-
-
- /*****************************************************************************/
-
- void __asm FreeBuffers( register __a6 struct DriverBase *db )
- {
- FlushStream(db);
-
- if (DMABuffer1)
- {
- FreeVec(DMABuffer1);
- DMABuffer1=NULL;
- }
- if (DMABuffer2)
- {
- FreeVec(DMABuffer2);
- DMABuffer2=NULL;
- }
- if (QueueBuffer)
- {
- FreeVec(QueueBuffer);
- QueueBuffer=NULL;
- }
-
- BUFFER_SIZE=0;
- QUEUE_SIZE=0;
- }
-
-
- /*****************************************************************************/
-
- BOOL __asm StreamFormat( register __d0 ULONG format, register __a6 struct DriverBase *db )
- {
- BOOL Success=FALSE;
-
- FlushStream(db);
-
- if ( (format==STREAM_16BIT_INTEL && CurrentFormat==STREAM_16BIT_MOTOROLA) ||
- (format==STREAM_16BIT_MOTOROLA && CurrentFormat==STREAM_16BIT_INTEL ) )
- {
- SwapEndian(ConversionTable);
- CurrentFormat=format;
- Success=TRUE;
- }
-
- return(Success);
- }
-
-
- /*****************************************************************************/
-
- ULONG __asm AskFrequency( register __d0 ULONG frequency, register __a6 struct DriverBase *db )
- {
- UWORD period;
- ULONG result;
-
- period=AskPeriod(frequency,db);
-
- result=(*(struct ExecBase**)(4))->ex_EClockFrequency*5/period;
-
- return(result);
- }
-
-
- /*****************************************************************************/
-
- ULONG __asm AskPeriod( register __d0 ULONG frequency, register __a6 struct DriverBase *db )
- {
- UWORD period;
- ULONG ModeID;
- struct MonitorInfo mon;
-
- /* See if front screen has changed */
- if (IntuitionBase->FirstScreen != CurrentScreen)
- {
- /* Store as new current screen and check for NULL ptr */
- if (CurrentScreen=IntuitionBase->FirstScreen)
- {
- /* Get mode ID */
- ModeID=GetVPModeID(&CurrentScreen->ViewPort);
-
- /* See if current mode ID has changed */
- if (ModeID != CurrentModeID)
- {
- /* Store as new current Mode ID */
- CurrentModeID=ModeID;
-
- /* Get information on current Mode ID */
- GetDisplayInfoData(NULL,(UBYTE*)&mon,sizeof(mon),DTAG_MNTR,ModeID);
-
- /* Calculate minimal period value for current ModeID */
- CurrentMinPer=mon.TotalColorClocks*mon.TotalRows/(2*(mon.TotalRows-mon.MinRow+1));
- }
- }
- }
-
- period=((*(struct ExecBase**)(4))->ex_EClockFrequency*5+(frequency/2))/frequency;
-
- if (period<CurrentMinPer) period=CurrentMinPer;
-
- return(period);
- }
-
-
- /*****************************************************************************/
-
- BOOL __asm ProvideStream( register __a0 UWORD *left,
- register __a1 UWORD *right,
- register __d0 ULONG samples,
- register __d1 UWORD interleave,
- register __d2 ULONG frequency,
- register __a2 void (*callback)(void),
- register __a6 struct DriverBase *db)
- {
- struct Custom *custom = (struct Custom*)0xdff000;
- struct StreamInfo *SI;
- BOOL Success=FALSE;
-
- DB(KPrintF("***SUPPLY(%ld) ",samples));
-
- /* Only supply if there are buffers to store it */
- if (QueueBuffer && DMABuffer1 && DMABuffer2)
- {
- /* check if there is enough room in the queue */
- if (((ProvidePos+1)%QUEUE_SIZE)!=PlayPos)
- {
- /* Arbitrate list by disabling the Audio Interrupt */
- SD_Lock(db);
-
- SI= &QueueBuffer[ProvidePos];
-
- SI->si_left=left;
- SI->si_right=right;
- SI->si_samples=samples;
- SI->si_interleave=interleave;
- SI->si_period=AskPeriod(frequency,db);
- SI->si_callback=callback;
- SI->si_offset=0;
-
- ProvidePos=(ProvidePos+1)%QUEUE_SIZE;
-
- /* Cause an audio interrupt if needed */
- if (DriverFlags & FLGF_NEEDIRQ)
- {
- DB(KPrintF("CAUSE "));
-
- DriverFlags &= (~FLGF_NEEDIRQ);
- custom->intreq = INTF_SETCLR|INTERRUPT_USED;
- }
-
- /* Re-enable Audio Interrupt */
- SD_Unlock(db);
-
- Success=TRUE;
- }
- else
- {
- DB(KPrintF("QUEUE FULL! "));
- }
- }
- else
- {
- DB(KPrintF("NO QUEUE! "));
- }
- DB(KPrintF("\n"));
- return(Success);
- }
-
-
- /*****************************************************************************/
-
- void __asm FlushStream( register __a6 struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- DB(KPrintF("***FLUSH "));
-
- /* Only flush if there is a queue to flush */
- if (QueueBuffer)
- {
- DB(KPrintF("CAUSE "));
-
- /* Set FLUSH flag and cause an audio interrupt */
- DriverFlags |= FLGF_FLUSH;
- custom->intreq=INTF_SETCLR|INTERRUPT_USED;
-
- /* Problem: Interrupt may occur somewhat delayed ;-( */
- /* This might speed it up a bit ;-) */
-
- custom->aud[0].ac_per=
- custom->aud[1].ac_per=
- custom->aud[2].ac_per=
- custom->aud[3].ac_per=1;
- }
- DB(KPrintF("\n"));
- }
-
-
- /*****************************************************************************/
-
- void __asm PauseStream( register __a6 struct DriverBase *db )
- {
- DB(KPrintF("***PAUSE "));
-
- /* set pause flag */
- DriverFlags |= FLGF_PAUSE;
-
- DB(KPrintF("\n"));
- }
-
-
- /*****************************************************************************/
-
- void __asm ResumeStream( register __a6 struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- DB(KPrintF("***RESUME "));
-
- /* clear pause flag */
- DriverFlags &= ~(FLGF_PAUSE);
-
- /* cause an audio interrupt if needed */
- if (DriverFlags & FLGF_NEEDIRQ)
- {
- DB(KPrintF("CAUSE "));
-
- DriverFlags &= (~FLGF_NEEDIRQ);
- custom->intreq = INTF_SETCLR|INTERRUPT_USED;
- }
-
- DB(KPrintF("\n"));
- }
-
-
- /*****************************************************************************/
-
- void __asm AudioInterrupt( register __d1 UWORD ActiveInt, register __a0 struct Custom * custom, register __a1 struct DriverBase *db, register __a6 SysBase )
- {
- struct StreamInfo *SI;
- UBYTE *Bufferptr;
- ULONG Chunklen,Playlen;
- UWORD Period=0;
- ULONG Pos;
- struct CIA *ciaa=(struct CIA*)0xbfe001;
-
- /* clear interrupt request bits */
- custom->intreq=(ActiveInt & INTERRUPT_USED);
-
- /* switch off audio filter */
- ciaa->ciapra |= CIAF_LED;
-
- DB(KPrintF("***IRQ "));
-
- /* Set period of the current DMA cycle */
- if (DriverFlags & FLGF_PLAYING)
- {
- custom->aud[0].ac_per=
- custom->aud[1].ac_per=
- custom->aud[2].ac_per=
- custom->aud[3].ac_per=LastPeriod;
- }
- else
- {
- /* Not playing? We we need an IRQ to restart */
- DriverFlags |= FLGF_NEEDIRQ;
- }
-
- /* Delete blocks that have been played completely */
- /* and delete ALL blocks if the FLUSH bit is set */
- for(PlayPos;PlayPos!=ProvidePos;PlayPos=(PlayPos+1)%QUEUE_SIZE)
- {
- SI= &QueueBuffer[PlayPos];
-
- if ((SI->si_offset == 0xffffffff) || (DriverFlags&FLGF_FLUSH))
- {
- DB(KPrintF("DELBLK "));
-
- /* See if this was the last block or if the FLUSH bit is set */
- if ((((PlayPos+1)%QUEUE_SIZE)==ProvidePos) || (DriverFlags&FLGF_FLUSH))
- {
- /* Stop DMA, nothing more to play */
- StopDMA(db);
- }
-
- /* Call callback hook */
- if (SI->si_callback) (SI->si_callback)();
- }
- else break;
- }
-
- /* Some more actions to take on FLUSH request */
- if (DriverFlags & FLGF_FLUSH)
- {
- DB(KPrintF("FLUSHED "));
-
- /* Reset pointers */
- CurrentBuffer=1;
- ProvidePos=0;
- PlayPos=0;
-
- /* Reset the flags bits */
- DriverFlags &= ~(FLGF_FLUSH|FLGF_PLAYING);
- DriverFlags |= FLGF_NEEDIRQ;
- }
- else
- {
- /* Mark blocks for deletion that are almost played */
- for (Pos=PlayPos;Pos!=ProvidePos;Pos=(Pos+1)%QUEUE_SIZE)
- {
- SI= &QueueBuffer[Pos];
-
- /* Block finished but still playing? */
- if (SI->si_offset==SI->si_samples)
- {
- DB(KPrintF("MARKDEL "));
-
- /* Mark block as deletable for next interrupt */
- SI->si_offset= 0xffffffff;
-
- /* See if we have a successor block */
- if (((Pos+1)%QUEUE_SIZE)==ProvidePos)
- {
- DB(KPrintF("NEEDIRQ "));
-
- /* No successor! We need an IRQ when one is provided */
- DriverFlags |= FLGF_NEEDIRQ;
- }
- }
- else break;
- }
-
- /* Actions to take on PAUSE request */
- if (DriverFlags & FLGF_PAUSE)
- {
- /* And stop the DMA right now */
- StopDMA(db);
- }
- else
- {
- /* Get current buffer pointer */
- if (CurrentBuffer == 1)
- {
- DB(KPrintF("BUF1 "));
- Bufferptr=DMABuffer1;
- }
- else
- {
- DB(KPrintF("BUF2 "));
- Bufferptr=DMABuffer2;
- }
-
- /* Fill buffer until filled */
- for (Playlen=0;(Playlen<BUFFER_SIZE) && (Pos!=ProvidePos);Pos=(Pos+1)%QUEUE_SIZE)
- {
- SI= &QueueBuffer[Pos];
-
- /* get length of current block */
- Chunklen = SI->si_samples-SI->si_offset;
- if (Chunklen>0)
- {
- /* maximize chunklen to buffer size */
- if (Chunklen > BUFFER_SIZE-Playlen)
- {
- Chunklen = BUFFER_SIZE-Playlen;
- }
-
- /* Make sure that period remains constant in one DMA cycle */
- if (Period)
- {
- if (Period != SI->si_period) break;
- }
- else
- {
- Period=SI->si_period;
- }
-
- DB(KPrintF("CONVERT(%ld,%ld) ",Chunklen,(ULONG)Period));
-
- /* Convert left channel */
- ConvertStream( SI->si_left+SI->si_offset*(SI->si_interleave+1),
- Bufferptr+LEFT_MSB+Playlen,
- Bufferptr+LEFT_LSB+Playlen,
- ConversionTable,
- Chunklen,
- SI->si_interleave);
-
- /* Convert right channel */
- ConvertStream( SI->si_right+SI->si_offset*(SI->si_interleave+1),
- Bufferptr+RIGHT_MSB+Playlen,
- Bufferptr+RIGHT_LSB+Playlen,
- ConversionTable,
- Chunklen,
- SI->si_interleave);
-
- /* Increment offset */
- SI->si_offset+=Chunklen;
-
- Playlen+=Chunklen;
- }
- }
-
- if (Playlen)
- {
- DB(KPrintF("PLAY(%ld,%ld) ",Playlen,(ULONG)Period));
-
- LastPeriod=Period;
-
- custom->aud[0].ac_ptr=(UWORD*)(Bufferptr+LEFT_MSB);
- custom->aud[1].ac_ptr=(UWORD*)(Bufferptr+RIGHT_MSB);
- custom->aud[2].ac_ptr=(UWORD*)(Bufferptr+RIGHT_LSB);
- custom->aud[3].ac_ptr=(UWORD*)(Bufferptr+LEFT_LSB);
-
- custom->aud[0].ac_vol=
- custom->aud[1].ac_vol=64;
- custom->aud[2].ac_vol=
- custom->aud[3].ac_vol=1;
-
- custom->aud[0].ac_len=
- custom->aud[1].ac_len=
- custom->aud[2].ac_len=
- custom->aud[3].ac_len=Playlen/2;
-
- /* If not already playing, start to do so */
-
- if (!(DriverFlags & FLGF_PLAYING))
- {
- DB(KPrintF("STARTDMA "));
-
- DriverFlags |= FLGF_PLAYING;
- custom->aud[0].ac_per=
- custom->aud[1].ac_per=
- custom->aud[2].ac_per=
- custom->aud[3].ac_per=Period;
- custom->dmacon = DMAF_SETCLR|DMAF_AUDIO;
- }
-
- /* Swap current buffer */
- if (CurrentBuffer == 1)
- {
- CurrentBuffer=2;
- }
- else
- {
- CurrentBuffer=1;
- }
- }
- }
- }
- DB(KPrintF("\n"));
- }
-
-
- /*****************************************************************************/
-
- void __asm StopDMA( register __a6 struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- /* If DMA active, stop it right now */
- if (DriverFlags&FLGF_PLAYING)
- {
- DB(KPrintF("STOPDMA "));
-
- /* Reset driver flags */
- DriverFlags &= (~FLGF_PLAYING);
- DriverFlags |= FLGF_NEEDIRQ;
-
- /* Stop the audio DMA */
- custom->dmacon = DMAF_AUDIO;
- custom->aud[0].ac_vol=
- custom->aud[1].ac_vol=
- custom->aud[2].ac_vol=
- custom->aud[3].ac_vol=0;
- }
- }
-
-
- /*****************************************************************************/
-
- void __asm NOPInterrupt(register __d1 UWORD ActiveInt, register __a0 struct Custom * custom, register __a1 struct DriverBase *db, register __a6 SysBase)
- {
- custom->intreq=(ActiveInt & INTERRUPTS_NOT_USED);
- }
-
-
- /*****************************************************************************/
-
- void __asm SD_Lock( register __a6 struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- if (NestLevel==0)
- {
- custom->intena=INTERRUPT_USED;
- }
- NestLevel++;
- }
-
-
- /*****************************************************************************/
-
- void __asm SD_Unlock( register __a6 struct DriverBase *db )
- {
- struct Custom *custom = (struct Custom*)0xdff000;
-
- if (NestLevel!=0)
- {
- NestLevel--;
- if (NestLevel==0)
- {
- custom->intena=INTF_SETCLR|INTERRUPT_USED;
- }
- }
- }
-